﻿//
//  ZDT3.cs
//
//  Author:
//       Antonio J. Nebro <antonio@lcc.uma.es>
//
//  Copyright (c) 2011 Antonio J. Nebro
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Lesser General Public License for more details.
// 
//  You should have received a copy of the GNU Lesser General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using jmetal.core;
using jmetal.encodings.solutionType;

namespace jmetal.problems
{
  public class ZDT3 : Problem
  {

    public ZDT3(String solutionType)
      : this(solutionType, 30)
    {
     // 30 variables by default
    } // ZDT1

    /**
     * Creates a new instance of problem ZDT1.
     * @param numberOfVariables Number of variables.
     * @param solutionType The solution type must "Real", "BinaryReal, and "ArrayReal". 
     */
    public ZDT3(String solutionType, int numberOfVariables)
    {
      // <pex>
      if (numberOfVariables < 0)
        throw new ArgumentException("numberOfVariables < 0", "numberOfVariables");
      // </pex>
      numberOfVariables_ = numberOfVariables;
      numberOfObjectives_ = 2;
      numberOfConstraints_ = 0;
      problemName_ = "ZDT3";

      upperLimit_ = new double[numberOfVariables_];
      lowerLimit_ = new double[numberOfVariables_];

      // Establishes upper and lower limits for the variables
      for (int var = 0; var < numberOfVariables_; var++)
      {
        lowerLimit_[var] = 0.0;
        upperLimit_[var] = 1.0;
      } // for

      solutionType_ = new RealSolutionType(this);
    } // ZDT1

    /** 
     * Evaluates a solution.
     * @param solution The solution to evaluate.
     * @throws JMException 
     */
    public override void evaluate (Solution solution)
    {
      // <pex>
      if (solution == (Solution)null)
        throw new ArgumentNullException("solution");
      if (solution.variable_ == (Variable[])null)
        throw new ArgumentNullException("solution");
      // </pex>
      Variable[] x = solution.variable_;

      double[] f = new double[numberOfObjectives_];
      f[0] = x[0].value_;
      double g = this.evalG (x);
      double h = this.evalH (f[0], g);
      f[1] = h * g;


      solution.objective_[0] = f[0];
      solution.objective_[1] = f[1];
    } // evaluate

    /**
     * Returns the value of the ZDT1 function G.
     * @param decisionVariables The decision variables of the solution to 
     * evaluate.
     * @throws JMException 
     */
    private double evalG(Variable[] x)
    {
    double g = 0.0;
    for (int i = 1; i < x.Length;i++)
      g += x[i].value_;
    double constante = (9.0 / (numberOfVariables_-1));
    g = constante * g;
    g = g + 1.0;
    return g;

    } // evalG

    /**
     * Returns the value of the ZDT1 function H.
     * @param f First argument of the function H.
     * @param g Second argument of the function H.
     */
    public double evalH(double f, double g)
    {
    double h = 0.0;
    h = 1.0 - Math.Sqrt(f/g)
        - (f/g)*Math.Sin(10.0*Math.PI*f);
    return h;

    } // evalH
  }
}
